/*******************************************************************************
 * Copyright (C), 2014, BeeIoT Tech. Co., Ltd. 
 * FileName:      SIM900A.c
 * Author:        lvxin 
 * Version :      1.0
 * Date:          2014-07-29 13:03:32
 * Description:
 * Function List: // 主要函数及其功能
 * 1. ------- 
 *  
 *                mdelay
 *                handle_sim_insert         //检测SIM卡是否插入       按需修改 
 *                _write                    //实现底层串口发送接口   *必须修改*
 *                recv_sm_callback          //收到短信后回调          按需修改
 *                idle_callback             //处理非命令状态下收到
 *                                          //的模块信息              按需修改
 *                cmd_callback              //命令行执行完回调        按需修改
 *                SIM900A_parse_input     //分析串口命令行数据      
 *                SIM900A_read              //底层串口中断方式按字节
 *                                          //传递数据，并处理        
 *                SIM900A_open              //打开模块               *必须修改*
 *                SIM900A_init              //模块初始化              
 *                SIM900A_run               //执行命令行              
 *                SIM900A_send_SM           //发送短信                按需修改
 * History:
 * <author>   <time>                <version >  <desc> 
 * lvxin      2014-07-29 13:03:32   1.0         build this moudle 
 * lvxin      2014-08-21 13:03:32   2.0         修改了idle_callback函数
 *                                              修改了SIM900A_send_PDU_SM()
 *                                              修改了l_pdu_msg_format数组
 ******************************************************************************/



/*******************************************************************************
 *  *INCLUDES
 *  */
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#include "option.h"
#include "smset.h"
#include "object.h"
#include "SIM900A.h"
#include "conv.h"
#include "gprs.h"
#include "pdu.h"


/*******************************************************************************
 *  *MICROS
 *  */
#define     DBG 1
#define     DIM(x)  (sizeof(x)/sizeof(x[0]))
#define     CYCLE_TIME  60 //定时查询sim卡注册状态的周期时间

/*******************************************************************************
 *  *EXTERNAL VARIABLES
 *  */

/*******************************************************************************
 *  *LOCAL FUNCTIONS DECLARE
 *  */

static void _recv_sm_callback(char *buffer);//处理收到的短信正文
/*static void recv_tcp_callback(char *buffer); //处理收到的tcp信息*/
static void _passive_callback(char *buffer);//被动模式下收到串口数据
static void _cds_handle(char *buffer);


static int _at_recv_CREG_cb(char *buffer);
static int _at_recv_CMT_cb(char *buffer);
static int _at_recv_RING_cb(char *buffer);
static int _at_recv_CALV_cb(char *buffer);
static int _at_recv_CONNECT_OK_cb(char *buffer);
static int _at_recv_CONNECT_FAIL_cb(char *buffer);
static int _at_recv_CLOSED_cb(char *buffer);
static int _at_recv_SEND_OK_cb(char *buffer);
static int _at_recv_SEND_FAIL_cb(char *buffer);
static int _at_recv_CDS_cb(char *buffer);
static int _at_recv_CIPSTATUS_cb(char *buffer);

/*******************************************************************************
 *  *LOCAL VARIABLES
 *  */
//AT指令接收到字符串的处理
const static at_recv_cb_t l_SIM900A_idle_recv_handle[]={
    {"+CREG: ",         _at_recv_CREG_cb},
    {"+CMT: ",          _at_recv_CMT_cb},
    {"+CDS: ",          _at_recv_CDS_cb},
    {"+CALV: ",         _at_recv_CALV_cb},
    {"+IPD",            at_recv_IPD_cb},
    {"SEND OK",         _at_recv_SEND_OK_cb},
    {"SEND FAIL",       _at_recv_SEND_FAIL_cb},
    {"CONNECT OK",      _at_recv_CONNECT_OK_cb},
    {"CONNECT FAIL",    _at_recv_CONNECT_FAIL_cb},
    {"ALREAY CONNECT",  _at_recv_CONNECT_FAIL_cb},
    {"CLOSED",          _at_recv_CLOSED_cb},
    {"STATE:",          _at_recv_CIPSTATUS_cb},
    {"RING",            _at_recv_RING_cb},
};


static option_t *l_option = NULL;

/*******************************************************************************
 *  *LOCAL FUNCTIONS
 *  */


//处理"+CREG: "
static int _at_recv_CREG_cb(char *buffer)
{
    return 0;
}

//处理"+CMT: "
static int _at_recv_CMT_cb(char *buffer)
{
    SIM900A_core_set_passive_cb (_recv_sm_callback);
    return 0;
}

//处理"+CDS: "
static int _at_recv_CDS_cb(char *buffer)
{
    SIM900A_core_set_passive_cb(_cds_handle);
    return 0;
}

//处理"RING"
static int _at_recv_RING_cb(char *buffer)
{
    static int ring_times = 0;
#if (PLATFORM == LPC1114)
    extern void ALERTER_CTRL(uint8_t on_off);
    ALERTER_CTRL (0);
#endif
#if (PLATFORM == LINUX)
    DBG_PRINTF ("来电\n");
#endif
    ring_times ++;
    if (ring_times >=2)
    {
        //通知主线程执行ATH挂机指令
        sm_inner_cmd_push_fifo(CMD_RUN_ATH, 0);
        ring_times = 0;
    }
    return 0;
}

//处理"+CALV: "
static int _at_recv_CALV_cb(char *buffer)
{
    sm_exec_query_balance(); //查询余额
    return 0;
}

//处理"SEND OK"
static int _at_recv_SEND_OK_cb(char *buffer)
{
    gprs_tcp_set_SENDOK();
    return 0;
}

//处理"SEND FAIL"
static int _at_recv_SEND_FAIL_cb(char *buffer)
{
    gprs_tcp_set_SENDFAIL();
    return 0;
}

//处理"CONNECT OK"
static int _at_recv_CONNECT_OK_cb(char *buffer)
{
    gprs_tcp_set_CONNOK();
    return 0;
}

//处理"CLOSED"
static int _at_recv_CLOSED_cb(char *buffer)
{
    //恢复被动数据处理函数
    SIM900A_core_set_passive_cb (_passive_callback);
    gprs_tcp_set_CLOSED();
    return 0;
}

//处理"STATE"
static int _at_recv_CIPSTATUS_cb(char *buffer)
{
    gprs_set_cip_statu(buffer+7); //更新cip状态
    return 0;
}

//处理"CONNECT FAIL"
static int _at_recv_CONNECT_FAIL_cb(char *buffer)
{
    
#if (PLATFORM == LINUX)
    DBG_PRINTF ("连接失败\n");
#endif
    gprs_tcp_set_FAIL();
    return 0;
}

/******************************************************************************
 * Function:        _get_cclk_time()
 * Description:     获取CCLK格式的时间
 * Calls:           string分割库
 * Called By:       SIM900A_get_monthday()
 * Called By:       SIM900A_get_year()
 * Called By:       SIM900A_get_timestamp())
 * Input:           object_t *con  --将object结构体传出
 * Return:          cclk格式的时间字符串
 * Others:          使用后需要调用object_free()释放con
 *****************************************************************************/
static object_t *_cclk_time_string_obj = NULL;
static int __cb_get_cclk_time(char *buffer, int len)
{
    /*object_t *tmp = NULL;*/
    /*if(SIM900A_run("AT+CCLK?\r\n", 2000, NULL, NULL) == AT_RETURN_OK)*/
    if (_cclk_time_string_obj != NULL) 
    {
        object_free(_cclk_time_string_obj);
    }
    if (buffer != NULL && len > 10)
    {
        DBG_PRINTF("[timebuf]%s\n", strstr(buffer,"+CCLK:"));
        _cclk_time_string_obj = object_string_split (
                strstr(buffer,"+CCLK:"),
                ':', NOQUOTES);
        return AT_RETURN_OK;
    }
    return AT_RETURN_ERROR;
}                           

static char * _get_cclk_time_string(object_t **con)
{
    char *date = NULL;
    if(SIM900A_run("AT+CCLK?\r\n", 2000, NULL, __cb_get_cclk_time) == AT_RETURN_OK)
    {
        date = object_string_get_field_string(_cclk_time_string_obj, 2);
    }
    *con = _cclk_time_string_obj;
    _cclk_time_string_obj = NULL;
    return date;
}

#if (PLATFORM == LINUX)
void memdump (void *first, int len)
{
    int line = 0;
    int i = 0;
    printf ("\n\033[1;33mADDRESS : ");
    for (i = 0; i < 16; i ++)
    {
        printf ("%02X ", i);
    }
    printf ("\033[0m");
    for (i = 0; i < len; i ++)
    {
        if (i%16==0)
        {
            printf ("\033[1;33m\n%08X: \033[0m", (line ++)*16);
        }
        printf ("%02X ", *((unsigned char *)first + i));
    }
    printf ("\n========================================\n");
}
#endif

//处理收到的短信正文
static void _recv_sm_callback(char *buffer)
{    
    char *tel_num = NULL;
#if (PLATFORM == LINUX)
    uint8_t date = 0;
#endif	
    int num_len = 0;


    char *content = NULL;
    size_t content_len = 0;
    uint8_t cds = 0;

    num_len = (conv_hex_ch_to_bin(buffer[20])*10
            +conv_hex_ch_to_bin(buffer[21])); //电话号码长度

    content = buffer+28+num_len+num_len%2+16;

    tel_num = conv_PDU_tel_to_normal_tel (buffer + 24, num_len + num_len %2);

    cds = conv_hex_ch_to_bin(*(buffer+27+num_len+num_len%2));



    /*l_monthday = date;*/
#if (PLATFORM == LINUX)
    DBG_PRINTF ("短信数据包：%s\n", buffer);
    DBG_PRINTF ("编码类型：%d\n", cds);
    date = (buffer[33+num_len+num_len%2]- '0')*10 
        + buffer[32+num_len+num_len%2] - '0' ;
    DBG_PRINTF ("短信来源：%s\n", tel_num);
    DBG_PRINTF ("短信日期：%d\n", date);
    DBG_PRINTF ("短信正文：%s\n", content);
    DBG_PRINTF ("[size]:   %d\n", strlen (buffer));
    DBG_PRINTF ("[contentlen]:   %d\n", strlen (content));
    DBG_PRINTF ("[utf8len]:   %d\n", strlen(content));
    DBG_PRINTF ("[utf8]:   %s\n", content);
    memdump (content, strlen (content));
#endif
    if ((strstr(tel_num, "10086") != NULL) ||  //匹配10086
            (strstr(tel_num, "10010") != NULL)     //匹配10010
       ) 
    {
        sm_query_balance(buffer); //分析短信余额
    }

    /*解析短信*/
    if (num_len > 8) //判断电话号码长度
    {
        sm_set_recipient (tel_num); //设置收信人
        content_len= strlen(content);

        switch (cds)
        {
            case 0 : //7bit编码转换
                conv_char_7bit_pdu_unpack (content, content_len, content, &content_len); 
                break;
            case 8 : //UCS2编码转换
                conv_pdu_to_utf8 (content, content_len, content, &content_len);    //转换短信为UTF8
                break;
            default :
                break;
        }
        sm_parse_data (content); //解析短信正文数据*/
    }

    free (tel_num);
    SIM900A_core_set_passive_cb (_passive_callback); //模块主动发送
}

//非命令状态下收到串口数据,被动模式
static void _passive_callback(char *buffer)
{
    int i;
    DBG_PRINTF ("[INPUT]%s", buffer);
    if (l_SIM900A_idle_recv_handle != NULL)
    {
        for (i = 0; i < DIM(l_SIM900A_idle_recv_handle) ; i ++)
        {
            /*if (strlen(buffer) >= strlen(l_SIM900A_idle_recv_handle[i].keyword))*/
            /*{*/
            if (strstr(buffer, l_SIM900A_idle_recv_handle[i].keyword) == buffer)
            {
                l_SIM900A_idle_recv_handle[i].callback (buffer);
                return;
            }
            /*}*/
        }
    }
}

//处理收到的CDS正文
static void _cds_handle(char *buffer)
{
    object_t *msg_head = NULL; //用来分割字符串
    char *cclk_date = NULL;
    msg_head = object_string_split(buffer + 6, ',', NOQUOTES); //避开"+CDS: "
#if (PLATFORM == LINUX)
    /*printf ("CDS头：%s\n", l_sim_cmdline.dest);*/
    /*printf ("短信时间：\"%s\"\n", time);*/
    printf ("CDS正文：%s\n", buffer); 
    printf ("[size]:   %d\n", strlen (buffer));
#endif
    if ((strstr(buffer, "0180F6") != NULL)
            ||(strstr(buffer, "0110F0") != NULL))
        cclk_date = conv_PDU_date_to_CCLK_date (buffer + 32);
    if (cclk_date != NULL)
    {
#if (PLATFORM == LINUX)
        printf ("发送时间：%s\n", cclk_date);
#endif
        sm_set_time (cclk_date); //设置时间
        free (cclk_date);
    }

    SIM900A_core_set_passive_cb (_passive_callback);
    object_free(msg_head); //释放文字处理
}


/*******************************************************************************
 *  *PUBLIC FUNCTIONS
 *  */

#if (PLATFORM == LPC1114)
int fputc(int ch, FILE *f)
{
        UART_SendByte((uint8_t)ch);
          return ch;
}
#endif

//获取设备ID
uint32_t SIM900A_get_device_id(void)
{
    if (l_option != NULL)
    {
        return l_option->dp[1].device_id;
    }
    return 0;
}

//获取全局配置参数
option_t *SIM900A_get_options(void)
{
    return l_option;
}

/*******************************************************************************
 * Function:      SIM900A_open()
 * Description:   启动并建立通信
 * Calls:         SIM900A_run()       
 * Called By:     main()
 * Input:         None
 * Return:        0   --打开成功
 *                -1  --打开失败
 * Others:        NONE
 ******************************************************************************/
int SIM900A_open(void)
{
    SIM900A_core_set_passive_cb (_passive_callback);
    return SIM900A_api_open ();
}

/*******************************************************************************
 * Function:      SIM900A_init()
 * Description:   初始化SIM900A
 * Calls:         SIM900A_sync_time()
 * Called By:     main()
 * Input:         serial --串口
 * Return:        none
 * Others:        NONE
 ******************************************************************************/
int SIM900A_init(option_t *option)
{
    int ret = 0;
    uint16_t time;
    l_option = option;
    ret = SIM900A_api_init();

    time = SIM900A_get_timestamp();
    srand(time);//初始化随机函数

    pdu_option_init(option);
    SIM900A_dpalarm_set_option(option);
    if (ret != -1)
    {
        gprs_init(l_option->alarm_mode);
        sm_inner_cmd_push_fifo (CMD_QUERY_BALANCE, 0); //查询余额并对时
    }
    return 0;
}

void SIM900A_reboot(void)
{
    sm_inner_cmd_push_fifo (CMD_HARD_REBOOT, 0);
}


//检查并处理sim卡注册状态
void SIM900A_check_regs(void)
{
    sm_inner_cmd_push_fifo (CMD_QUERY_SIM_REGSTAT, 0); //检查sim卡注册状态
}

/******************************************************************************
 * Function:        SIM900A_main_loop()
 * Description:     处理SIM900A的应用的主线程
 * Calls:           sm_inner_cmd_loop()
 * Called By:       main()
 * Input:           void
 * Return:          void
 * Others:          主程序需要周期性调用该函数
 *****************************************************************************/
void SIM900A_main_loop()
{
    sm_inner_cmd_loop ();
}

/*******************************************************************************
 * Function:      SIM900A_get_timestamp()
 * Description:   获得系统时间戳
 * Calls:         SIM900A_run()
 * Called By:     
 * Input:         None
 * Return:        uint16_t 格式的时间 高8位小时 低8位分钟
 * Others:        None
 ******************************************************************************/
uint16_t SIM900A_get_timestamp(void)
{
    uint8_t mm = 0;
    uint8_t hh = 0;
    char *date = NULL;

    object_t *tmp = NULL;
    date = _get_cclk_time_string(&tmp);

    if (date != NULL)
    {
        hh = ((date[10] - '0')*10 + (date[11] - '0')) % 24;
        mm = ((date[13] - '0')*10 + (date[14] - '0')) % 60;
    }
    object_free(tmp);
    return ((hh<<8) + mm);
}

/*******************************************************************************
 * Function:      SIM900A_get_monthday()
 * Description:   获得系统日期
 * Calls:         SIM900A_run()
 * Called By:     
 * Input:         None
 * Return:        uint16_t 格式的时间 高8位小时 低8位分钟
 * Others:        None
 ******************************************************************************/
uint8_t SIM900A_get_monthday(void)
{
    char *date = NULL;
    uint8_t day = 0;
    object_t *tmp = NULL;
    
    date = _get_cclk_time_string(&tmp);
    if (date != NULL)
    {
        day = ((date[7] - '0')*10 + (date[8] - '0')) % 32;
    }
    object_free(tmp);
    return day;
}

/******************************************************************************
 * Function:        SIM900A_get_year()
 * Description:     获得系统时间的年份
 * Calls:           _get_cclk_time()
 * Called By:        
 * Input:            
 * Return:          uint8_t --两位的年份后两位数字，如2012年为12
 * Others:              
 *****************************************************************************/
uint8_t SIM900A_get_year(void) //获得年
{
    char *date = NULL;
    uint8_t year = 1;
    object_t *tmp = NULL;

    date = _get_cclk_time_string(&tmp);
    if (date != NULL)
    {
        year = (date[1] - '0')*10 + (date[2] - '0');
    }
    object_free(tmp);
    return year;
}

//设置系统时间
/*******************************************************************************
 * Function:      SIM900A_set_time()
 * Description:   设置系统时间
 * Calls:         
 * Called By:     
 * Input:         uint16_t 格式的时间 高8位小时 低8位分钟
 * Return:        0 --设置成功  -1 --设置失败
 * Others:        None
 ******************************************************************************/
int SIM900A_set_time(uint16_t time)
{
    int ret = -1;
    uint8_t hh = (time>>8) % 24;
    uint8_t mm = (time & 0xff) % 60;

    char *date = NULL;
    object_t *tmp = NULL;

    date = _get_cclk_time_string(&tmp);
    if (date != NULL)
    {
        date[10] = hh/10 + '0';
        date[11] = hh%10 + '0';
        date[13] = mm/10 + '0';
        date[14] = mm%10 + '0';

        ret = SIM900A_perform_formatted (3000, NULL, NULL, "AT+CCLK=\"%s\"\r\n", date+1);
    }
    object_free(tmp);
    return ret;
}

static char l_phone_num[12] = {0};
//获取系统保存的手机号码
char *SIM900A_get_telnum()
{
    int i;
    for (i = 0; i < 11; i ++)
    {
        if (*(l_option->telephone[0].number + i) > 9) 
        {
            memset (l_phone_num, 0, 12); //号码数字范围
            return l_phone_num;
        }
        l_phone_num[i] = l_option->telephone[0].number[i] + '0';
    }
    return l_phone_num;
}

#if (PLATFORM == LINUX)
void *SIM900A_thread_cycle_check_regs(void *arg) 
{
    DBG_PRINTF ("SIM卡检测开始\n");
    while (1)
    {
        sleep (CYCLE_TIME);
        SIM900A_check_regs();
    }
    return NULL;
}
#endif

#if (PLATFORM == LPC1114)
/*********************************************************************************************************
 * * Function Name:        TIMER32_0_IRQHandler
 * * Description:          TIMER0 中断处理函数
 * * Input:                无
 * * Output:               无
 * * Return:               无
 * *********************************************************************************************************/
void TIMER32_0_IRQHandler (void)
{
	static int a=0;
    LPC_TMR32B0->IR = 0x01;                                             /* 清除中断标志                 */
    SIM900A_check_regs();
	a++;
	if(a>=3) LPC_SYSCON->SYSAHBCLKCTRL &= ~(1 << 9);	
}


/*********************************************************************************************************
 * ** Function name:        timer0Init
 * ** Descriptions:        32位定时器0初始化函数
 * ** input parameters:    无
 * ** output parameters:   无
 * ** Returned value:      无
 * *********************************************************************************************************/
void timer0Init (void)
{
    LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 9);                              /* 打开定时器模块               */

    LPC_TMR32B0->IR      = 1;
    LPC_TMR32B0->PR      = 1000;                                        /* 设置分频系数                 */
    LPC_TMR32B0->MCR     = 3;                                           /* 设置MR0匹配后复位TC并产生中断*/
    LPC_TMR32B0->MR0     = SystemFrequency/1000 * CYCLE_TIME;           /* 设置中断时间 60s             */    
    LPC_TMR32B0->TCR     = 0x01;                                        /* 启动定时器                   */
    NVIC_EnableIRQ(TIMER_32_0_IRQn);                                    /* 设置中断并使能               */
    NVIC_SetPriority(TIMER_32_0_IRQn, 2);
}
#endif

